#include "VectorMath.h"

//constructor
template<class T>
VectorMath<T> :: VectorMath(unsigned dim){
    nums = new T[ dim ];
    this->dim = dim;
    
    for( unsigned i = 0 ; i < dim ; i++ )
        nums[i] = 0;
}

//constructor de copia
template<class T>
VectorMath<T> :: VectorMath(const VectorMath<T> & vec){
    nums = new T[ vec.dim ];
    for( unsigned i = 0 ; i < vec.dim ; i++ )
        (*this)[i] = vec[i];
    
    dim = vec.dim;
}

//destructor
template<class T>
VectorMath<T> :: ~VectorMath(){
    delete [] nums;
}

//getter dimension
template<class T>
unsigned VectorMath<T> :: size()const{
    return dim;
}

//resize
template<class T>
void VectorMath<T> :: resize( unsigned newSize ){
    
    VectorMath<T> oldVec( (*this) );
    
    delete [] nums;
    
    nums = new T[ newSize ];
    this->dim = newSize;
    
    unsigned i;
    
    for( i = 0 ; i < oldVec.size() ; i++ )
        nums[i] = oldVec[i];
    
    for(; i < dim ; i++ )
        nums[i] = 0;
    
}

//operator []
template<class T>
T& VectorMath<T> :: operator [](unsigned i){
    return nums[i];
}
//operator [] const
template<class T>
T VectorMath<T> :: operator [](unsigned i) const{
    T num = nums[i];
    return num;
}

//operator =
template<class T>
VectorMath<T> & VectorMath<T> :: operator = (const VectorMath<T> & vec){
    
    if( vec.dim != dim ){
        delete [] nums;
        nums = new T[ vec.dim ];
        dim = vec.dim;
    }
    
    for( unsigned i = 0 ; i < vec.dim ; i++ )
        (*this)[i] = vec[i];
    
    dim = vec.dim;
    
    return (*this);
}

//operator +
template<class T>
VectorMath<T> VectorMath<T> :: operator + (const VectorMath<T> & vec) const{
    VectorMath sum;
    
    if( sum.dim != vec.dim )
        return sum;
    
    sum = (*this);
    
    for( unsigned i = 0 ; i < sum.dim ; i++ )
        sum[i] += vec[i];
    
    return sum;
    
}

//operator +
template<class T>
VectorMath<T> VectorMath<T> :: operator - (const VectorMath<T> & vec) const{
    VectorMath sub;
    
    if( sub.dim != vec.dim )
        return sub;
    
    sub = (*this);
    
    for( unsigned i = 0 ; i < sub.dim ; i++ )
        sub[i] -= vec[i];
    
    return sub;
}

//operator * (producto vectorial)
template<class T>
VectorMath<T> VectorMath<T> :: operator * (const VectorMath<T> & vec) const{
    VectorMath prod( 3 );
    //El producto vectorial esta definido solo para la dimension 3.
    if( vec.dim == 3 && dim == 3 ){
        prod[0] = nums[2] * vec[3] - nums[3] * vec[2];
        prod[1] = nums[3] * vec[1] - nums[1] * vec[3];
        prod[2] = nums[1] * vec[2] - nums[2] * vec[1];
    }
    
    return prod;
}

//operator * T
template<class T>
VectorMath<T> VectorMath<T> :: operator*( const T num ) const{
    VectorMath<T> vec( (*this) );
    
    for( unsigned i = 0 ; i < dim ; i++ )
        vec[i] *= num;
    
    return vec;
    
}

//operator ==
template<class T>
bool VectorMath<T> :: operator == (const VectorMath<T> & vec) const{
    if( dim != vec.dim ) return false;
    
    for( unsigned i = 0 ; i < dim ; i++ )
        if( nums[i] != vec[i] ) return false;
    
    return true;
}

//norma
template<class T>
T VectorMath<T> :: norma(){
    T sum = 0.0;
    
    for(unsigned i = 0 ; i < dim ; i++)
        sum += nums[i] * nums[i];
        
    return sqrt( sum );
}

//toString
template<class T>
string VectorMath<T> :: toString(){
    string vecToString;
    
    ostringstream stream;
    stream << dim << "\n";
    
    for( unsigned i = 0 ; i < dim ; i++ )
        stream << nums[i] << "\n";
    
    vecToString = stream.str();

    return vecToString;
}

//test
//se prueba poniendo esto en el main 
//VectorMath<float>::test();
template<class T>
bool VectorMath<T> :: test(){
    VectorMath<float> vec;
    
    vec.resize(4);
    
    for(unsigned i = 0; i < vec.size(); i++)
            vec[i] = 2;
            
    VectorMath<float> vec2(vec);
    
    if(vec == vec2) cout << "iguales" << endl;
    
    for(unsigned i = 0; i < vec.size(); i++)
            cout << vec2[i] << endl;
    
    cout << vec.norma() << endl;
    
    return true;
}
